package com.mybatisflex.demo.config;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.core.FlexGlobalConfig;
import com.mybatisflex.core.audit.AuditManager;
import com.mybatisflex.core.audit.ConsoleMessageReporter;
import com.mybatisflex.core.audit.ScheduledMessageCollector;
import com.mybatisflex.core.datasource.DataSourceManager;
import com.mybatisflex.core.datasource.FlexDataSource;
import com.mybatisflex.core.keygen.KeyGeneratorFactory;
import com.mybatisflex.core.keygen.KeyGenerators;
import com.mybatisflex.core.keygen.impl.SnowFlakeIDKeyGenerator;
import com.mybatisflex.core.logicdelete.LogicDeleteManager;
import com.mybatisflex.core.logicdelete.impl.IntegerLogicDeleteProcessor;
import com.mybatisflex.core.mask.MaskManager;
import com.mybatisflex.core.mybatis.FlexConfiguration;
import com.mybatisflex.core.table.TableManager;
import com.mybatisflex.core.tenant.TenantManager;
import com.mybatisflex.demo.audit.AuditMessageFactory;
import com.mybatisflex.demo.dynamic.MyDynamicTableProcessor;
import com.mybatisflex.demo.entity.Account;
import com.mybatisflex.demo.entity.Card;
import com.mybatisflex.demo.keygen.HashCodeKeyGenerator;
import com.mybatisflex.demo.listener.LoggerListener;
import com.mybatisflex.demo.mask.IdNumberMaskProcessor;
import com.mybatisflex.demo.tenant.TenantIdFactory;
import com.mybatisflex.spring.boot.ConfigurationCustomizer;
import com.mybatisflex.spring.boot.MyBatisFlexCustomizer;
import com.mybatisflex.spring.boot.SqlSessionFactoryBeanCustomizer;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.logging.stdout.StdOutImpl;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Configuration;

import java.util.Base64;

/**
 * @author 王帅
 * @since 2023-07-07
 */
@Slf4j
@Configuration
@SuppressWarnings("all")
public class MybatisFlexConfig implements
        ConfigurationCustomizer,
        SqlSessionFactoryBeanCustomizer,
        MyBatisFlexCustomizer,
        ApplicationRunner {

    @Override
    public void customize(FlexConfiguration configuration) {
        configuration.setLogImpl(StdOutImpl.class);
        System.out.println("MyBatis Configuration 配置！");
    }

    @Override
    public void customize(SqlSessionFactoryBean factoryBean) {
        System.out.println("SqlSessionFactoryBean 配置！");
    }

    @Override
    public void customize(FlexGlobalConfig globalConfig) {
        System.out.println("MyBatis Flex 配置！");
        LoggerListener loggerListener = new LoggerListener();
        globalConfig.registerInsertListener(loggerListener, Account.class, Card.class);
        globalConfig.registerUpdateListener(loggerListener, Account.class, Card.class);

        FlexGlobalConfig.KeyConfig keyConfig = new FlexGlobalConfig.KeyConfig();
        keyConfig.setKeyType(KeyType.Auto);
        keyConfig.setValue("");
        keyConfig.setBefore(true);

        globalConfig.setKeyConfig(keyConfig);

        KeyGeneratorFactory.register("hashCode", new HashCodeKeyGenerator());
        KeyGeneratorFactory.register(KeyGenerators.snowFlakeId, new SnowFlakeIDKeyGenerator(1, 1));

        globalConfig.setNormalValueOfLogicDelete(0);
        globalConfig.setDeletedValueOfLogicDelete(2);

        LogicDeleteManager.setProcessor(new IntegerLogicDeleteProcessor());

        TenantManager.setTenantFactory(new TenantIdFactory());

        MaskManager.registerMaskProcessor("idNumber", new IdNumberMaskProcessor());

//        DialectFactory.registerDialect(DbType.MYSQL, new DataPermissionDialect());

        DataSourceManager.setDecipher(((property, value) -> switch (property) {
            case URL -> value.startsWith("jdbc") ? value : new String(Base64.getDecoder().decode(value));
            case PASSWORD, USERNAME -> value;
        }));

        TableManager.setDynamicTableProcessor(new MyDynamicTableProcessor());

        // 开启审计功能
        AuditManager.setAuditEnable(true);

        AuditManager.setMessageFactory(new AuditMessageFactory());
//        AuditManager.setMessageReporter(new ConsoleMessageReporter());
        AuditManager.setMessageCollector(new ScheduledMessageCollector(5, new ConsoleMessageReporter()));

        // 设置 SQL 审计收集器
//        AuditManager.setMessageCollector(new ConsoleMessageCollector());

//        AuditManager.setMessageCollector(auditMessage ->
//                log.info("{}, {} ms", auditMessage.getFullSql(), auditMessage.getElapsedTime()));
    }

    /*@Bean
    public DataSourceDecipher dataSourceDecipher() {
        return (property, value) -> switch (property) {
            case URL -> value.startsWith("jdbc") ? value : new String(Base64.getDecoder().decode(value));
            case PASSWORD, USERNAME -> value;
        };
    }*/

    @Override
    public void run(ApplicationArguments args) {
        FlexDataSource flexDataSource = FlexGlobalConfig.getDefaultConfig().getDataSource();

        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        String rawValue = "jdbc:mysql://localhost:3306/flex_demo";
        String jdbcUrl = Base64.getEncoder().encodeToString(rawValue.getBytes());
        System.out.println("加密 JDBC URL 为：" + jdbcUrl);
        dataSource.setJdbcUrl(jdbcUrl);
        dataSource.setUser("root");
        dataSource.setPassword("12345678");

        flexDataSource.addDataSource("ds5", dataSource);
    }

}